#include "mqttdevicereg.h"
#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)        
#include "qassert.h"
#endif
#include <QDebug>
#include <QJsonParseError>
#include <QTimer>

MqttDeviceReg::MqttDeviceReg(QMap<QString,QString> necessary,QObject *parent)
    : QObject{parent}
{
    qDebug()<<"> "<<__func__<<"thread id:"<<QThread::currentThreadId();
    
    Q_ASSERT_X(necessary.size()>0,"MqttDeviceReg::MqttDeviceReg","necessary not null");
    Q_ASSERT_X(necessary.contains("productKey"),"MqttDeviceReg::MqttDeviceReg","Not productKey");
    m_productKey = necessary.value("productKey");
    m_username = m_productKey;
    
    Q_ASSERT_X(necessary.contains("clientId"),"MqttDeviceReg::MqttDeviceReg","Not clientId");
    m_client = necessary.value("clientId");
    
    Q_ASSERT_X(necessary.contains("productSecret"),"MqttDeviceReg::MqttDeviceReg","Not productSecret");
    m_productSecret = necessary.value("productSecret");
    m_password = m_productSecret;
    
    Q_ASSERT_X(necessary.contains("deviceName"),"MqttDeviceReg::MqttDeviceReg","Not deviceName");
    m_deviceName = necessary.value("deviceName");
    
    Q_ASSERT_X(necessary.contains("hostname"),"MqttDeviceReg::MqttDeviceReg","Not hostname");
    m_hostname = necessary.value("hostname");
    
    Q_ASSERT_X(necessary.contains("port"),"MqttDeviceReg::MqttDeviceReg","Not port");
    m_port = necessary.value("port").toULong();
    
    initTopicMap();
    
}

MqttDeviceReg::~MqttDeviceReg()
{
    qDebug()<<"> ~MqttDeviceReg()";
}

void MqttDeviceReg::initTopicMap()
{
    m_topicMap.insert(Topic::Device_register,QString("/sys/%1/%2/%3/register").arg(m_productKey,m_productSecret,m_deviceName));
    m_topicMap.insert(Topic::Device_register_reply,QString("/sys/%1/%2/%3/register_reply").arg(m_productKey,m_productSecret,m_deviceName));
}

void MqttDeviceReg::mqttMonitor()
{
    if(m_mqttClient){
        qDebug()<<"< mqttMoitor() retry initialize!";
        return;
    }
    m_mqttClient = new QMqttClient(this);
    m_mqttClient->setClientId(m_client);
    m_mqttClient->setUsername(m_username);
    m_mqttClient->setPassword(m_password);
    m_mqttClient->setHostname(m_hostname);
    m_mqttClient->setPort(m_port);
    
    qDebug()<<"> mqtt register clent status:"<<m_mqttClient->state();
    connect(m_mqttClient,&QMqttClient::connected,this,&MqttDeviceReg::onConnected);
    connect(m_mqttClient,&QMqttClient::stateChanged,this,&MqttDeviceReg::onMqttState);
    m_mqttClient->connectToHost();
}

void MqttDeviceReg::onMqttState(QMqttClient::ClientState state)
{
    qDebug()<<"> MqttDeviceReg::onMqttState state:"<<state;
    if (state == QMqttClient::Disconnected) {
        qDebug() << "MQTT client disconnected. Attempting to reconnect...";
        QTimer::singleShot(5*1000,[&](){
            m_mqttClient->connectToHost();
        });
    }
}

bool MqttDeviceReg::isMqttdisconnServer()
{
    if(!m_mqttClient)
        return false;
    
    return (m_mqttClient->state() == QMqttClient::Disconnected);
}

bool MqttDeviceReg::publishTheme(Topic topic,QJsonObject jsobj)
{
    if(isMqttdisconnServer())
        return false;
    QJsonDocument jsDoc;
    jsDoc.setObject(jsobj);
    QByteArray body = jsDoc.toJson();
    
    m_mqttClient->publish(QMqttTopicName(getTopic(topic)));
    
    return true;
}

void MqttDeviceReg::onConnected()
{
    qDebug()<<"> onConnected() device mqtt connected!";
    qDebug()<<"> onConnected() subscribe theme!";
    auto subscription = m_mqttClient->subscribe(QMqttTopicFilter(getTopic(Topic::Device_register_reply)));
    
    if(!subscription){
        qCritical()<< "Failed to subscribe to topic";
        return;
    }
    connect(subscription, &QMqttSubscription::messageReceived, this,&MqttDeviceReg::onMessgeReceived,Qt::UniqueConnection);
    qDebug()<<"> mqtt theme publish!";
    m_mqttClient->publish(QMqttTopicName(getTopic(MqttDeviceReg::Topic::Device_register)));
}

void MqttDeviceReg::onMessgeReceived(const QMqttMessage &msg)
{
    qDebug()<<">> "<<__func__;
    
    QJsonParseError e;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(msg.payload(),&e);
    QJsonObject jsobj = jsonDoc.object();
    emit register_reply(jsobj);
}

QString MqttDeviceReg::getTopic(Topic topic)
{
    return m_topicMap.value(topic);
}


